<template>
  <div>
    <el-table
      v-if="columnList.length > 0"
      :key="0"
      v-loading="listLoading"
      :data="items"
      border
      fit
      highlight-current-row
      style="width: 100%;"
      @selection-change="handleSelectionChange"
      @sort-change="handleSortChange"
    >
      <el-table-column
        type="selection"
        align="center"
        width="60"
      />
      <el-table-column
        v-for="column in columnList"
        :key="column.$index"
        :align="column.align ? column.align : 'center'"
        :label="column.label"
        :width="column.width"
        :class-name="column.className"
        :fixed="column.traits | traitFilter('fixed')"
        :sortable="column.traits | traitFilter('sortable')"
        :prop="column.field"
      >
        <template v-slot="{row}">
          <table-item
            :column="column"
            :row="row"
            :primary-key="primaryKey"
            :is-allow-update="isAllowUpdate"
            @handle-operation="handleOperation"
            @form-submit="handleFormSubmit"
            @form-cancel="handleFormCancel"
          >
            <template v-slot:string>
              {{ row[column.field] }}
            </template>
            <template v-slot:image>
              <el-image
                :src="row[column.field] === '' ? defaultImage : row[column.field]"
                :preview-src-list="row[column.field] === '' ? [defaultImage] : [row[column.field]]"
                style="max-width: 120px"
              />
            </template>
            <template v-slot:images>
              <el-popover
                placement="bottom"
                width="600"
                trigger="hover"
              >
                <div class="images-body">
                  <div v-for="(item, key) in parseImageList(row[column.field])" :key="key" class="images-item">
                    <el-image
                      class="images-item"
                      :src="item"
                      :preview-src-list="[item]"
                    />
                  </div>
                </div>
                <div slot="reference" class="images-wrap">
                  <div v-for="(item, key) in parseImageList(row[column.field])" :key="key" class="images-item-small">
                    <el-image
                      class="images-item"
                      :src="item"
                    />
                  </div>
                </div>
              </el-popover>

            </template>
            <template v-slot:int>
              <span>{{ parseInt(row[column.field]) }}</span>
            </template>
            <template v-slot:datetime>
              <span>{{ row[column.field] | parseTime(column.format) }}</span>
            </template>
            <template v-slot:timestamp>
              <span>{{ row[column.field] | parseTime(column.format) }}</span>
            </template>
            <template v-slot:tag>
              <el-tag :type="row[column.field] | typesFilter(typesMap[column.field])">
                {{ row[column.field] | selectFilter(column.options) }}
              </el-tag>
            </template>
            <template v-slot:radio>
              <i v-if="row[column.field] === 1" class="el-icon-circle-check" style="color: #67C23A" />
              <i v-else-if="row[column.field] === 0" class="el-icon-circle-close" />
            </template>
            <template v-slot:select>
              <el-tag type="info" effect="plain">
                {{ row[column.field] | selectFilter(column.options) }}
              </el-tag>
            </template>
            <template v-slot:file>
              <a :href="row[column.field] || 'javascript:;'" target="_blank">
                <el-button :type="row[column.field] ? 'primary' : 'info'" size="mini">
                  点击下载
                </el-button>
              </a>
            </template>
            <template v-slot:files>
              <div>
                <div v-for="(item, index) in parseFileList(row[column.field])">
                  <a :href="item || 'javascript:;'" target="_blank">
                    <el-button :type="item ? 'primary' : 'info'" size="mini">
                      点击下载
                    </el-button>
                  </a>
                </div>
              </div>
            </template>
            <template v-slot:operations>
              <div />
            </template>
            <template v-slot:switch>
              <div />
            </template>
          </table-item>
        </template>
      </el-table-column>
    </el-table>
    <pagination
      v-show="total>0"
      :total="total"
      :page.sync="listQuery.page"
      :limit.sync="listQuery.limit"
      @size-change="handleSizeChange"
      @pagination="getList"
    />
  </div>
</template>

<script>
import Pagination from '@/components/Pagination' // 分页
import TableItem from './table-item' // 表格列
import { getQueryObject, parseTime, formatOptions, jsonParse } from '@/utils'
import { fetchList } from '@/api/complex/table'

const DEFAULT_IMAGE = 'http://cdn.wecut.com/matrix/pocket/default/resource/upload/20200717/a5fda41c69b5f4b06f990e971e06d74b.png'

export default {
  name: 'TableIndex',
  components: { TableItem, Pagination },
  filters: {
    // 图片列表 json转换成对象数组
    imageListFilter(images) {
      images = images === '' ? [DEFAULT_IMAGE] : images
      if (images instanceof Array) {
        return images
      } else {
        return jsonParse(images)
      }
    },
    imageFilter(images) {
      images = images === '' ? [DEFAULT_IMAGE] : images
      if (images instanceof Array) {
        return images[0]
      } else {
        return jsonParse(images)[0]
      }
    },
    // 标签过滤显示 兼容旧options
    typesFilter(value, options) {
      if (!options) {
        return 'default'
      } else if (options instanceof Array) {
        for (const k in options) {
          if (options[k].value === value) {
            return options[k].label
          }
        }
      } else {
        return options[value] ? options[value] : 'default'
      }
      return 'default'
    },
    // 下拉框过滤显示 兼容旧options
    selectFilter(value, options) {
      if (!options) {
        return value
      } else if (options instanceof Array) {
        if (value instanceof Array) {
          let string = ''
          for (const k in options) {
            if (value.indexOf(options[k].value) >= 0) {
              string += options[k].label + '\n'
            }
          }
          return string
        } else {
          for (const k in options) {
            if (options[k].value === value) {
              return options[k].label
            }
          }
        }
      } else {
        return options[value] ? options[value] : value
      }
    },
    // 特征过滤
    traitFilter(traits, trait) {
      if (traits) {
        for (let i = 0; i < traits.length; i++) {
          if (traits[i] === trait) {
            if (trait === 'sortable') {
              // 接口排序
              return 'custom'
            } else {
              return true
            }
          }
        }
      }
      return false
    },
    // 时间转换
    parseTime(timestamp, format) {
      format = format || '{y}-{m}-{d} {h}:{i}'
      return parseTime(timestamp, format)
    }
  },
  // eslint-disable-next-line vue/require-prop-types
  props: ['list', 'listLoading', 'tableHeaders', 'listQuery', 'total', 'primaryKey'],
  data() {
    return {
      // 字段列表 tableHeaders解除绑定
      columnList: [],
      // 表格列表 list解除绑定
      items: [],
      // 把字段中的所有option抽离出来存成哈希 便于获取
      optionMap: {},
      // 是否允许更新 (由于列表显示的时候会触发handleInputChange 所以要延时1s才允许更新)
      isAllowUpdate: false,
      // 默认图
      defaultImage: DEFAULT_IMAGE,
      // 显示样式
      typesMap: {}
    }
  },
  computed: {
    // 页码
    page() {
      return this.listQuery.page
    }
  },
  watch: {
    tableHeaders() {
      // 过滤不在列表显示的字段
      this.columnList = this.tableHeaders.map(item => {
        const column = Object.assign({}, item) // 复制值 不影响原来的值
        if (column.type === 'switch') {
          // 默认添加switch按钮操作
          if (
            !column.operations.includes(operation => {
              return operation.action === 'form'
            })
          ) {
            column.operations.push({
              action: 'form'
            })
          }
        }

        // 更改列表的显示类型
        column.operations.map(operation => {
          if (operation.action === 'listType') {
            column.type = operation.type
            // 把 types 保存到 typesMap
            if (operation.types) {
              this.typesMap[column.field] = formatOptions(operation.types)
            }
          }
        })

        return column
      }).filter((column) => {
        // 只在列表显示
        return (column.showStatus & 1) === 1
      })
    },
    list() {
      this.items = this.list
      const operationMap = {}
      // 把operation 轮询 放到 operationMap 附带input 和 values(列表中该字段的所有值)
      this.columnList.map((column) => {
        if (column.operations.length > 0) {
          operationMap[column.field] = {}
          column.operations.forEach(operation => {
            const input = column
            const values = []
            this.list.map((row, index) => {
              for (const k in row) {
                if (k === column.field) {
                  values.push(row[k])
                }
              }
            })
            operationMap[column.field][operation.action] = { ...operation, input, values }
          })
        }
        return column
      })

      // 轮询调用handleOperationPrepare作准备
      for (const k in operationMap) {
        for (const action in operationMap[k]) {
          const { values, input, ...operation } = operationMap[k][action]
          this.handleOperationPrepare(values, operation, input)
        }
      }
    }
  },
  beforeUpdate() {
    this.isAllowUpdate = false
  },
  updated() {
    this.isAllowUpdate = true
  },
  methods: {
    // 页码发生改变 修改页码cookie
    handleSizeChange(val) {
      this.$store.dispatch('app/setPageSize', val)
    },
    // 触发父组件获取列表信息
    getList() {
      this.$emit('get-list')
    },
    // 触发父组件处理操作
    handleOperation({ operation, row, column }) {
      this.$emit('operation-click', { operation, row, column })
    },
    // 触发父组件处理选中多行
    handleSelectionChange(rows) {
      this.$emit('selection-change', rows)
    },
    // 排序改变 -> 请求列表接口刷新数据
    handleSortChange({ prop, order }) {
      const orderMap = {
        ascending: 'asc',
        descending: 'desc'
      }
      if (!this.listQuery.sort) {
        this.listQuery.sort = {}
      }
      this.listQuery.sort[prop] = orderMap[order]

      this.getList()
    },
    // 操作的准备事项 主要是做请求接口来显示数据相关的操作
    handleOperationPrepare(values, operation, input) {
      // 在列表中显示的字段才做进一步查询
      const res = this.columnList.find(column => {
        return column.field === operation.field
      })
      if (res === undefined) {
        return
      }

      const handler = operation.action + 'Handler'
      if (typeof this[handler] === 'function') {
        this[handler]({ operation, input, values })
      }
    },
    // 请求接口获取options来改变另一个字段的options值
    async changeOptionsHandler({ operation, input, values }) {
      const queryObject = getQueryObject(operation.url)
      // 去重
      values = Array.from(new Set(values))
      this.optionMap[input.field] = []

      // 从接口获取数据 -> 临时保存直到所有接口请求完毕
      for (const i in values) {
        const reg = new RegExp('{' + input.field + '}', 'g')
        const param = {}
        param[input.field] = queryObject[input.field].replace(reg, values[i])

        const optionsTemp = await fetchList(operation.url, param).then(response => {
          return response.data.options || response.data.list || []
        })
        this.optionMap[input.field].push(...optionsTemp)
      }
      // 替换对应字段的options
      this.columnList = this.columnList.map(column => {
        if (column.field === operation.field) {
          const options = this.optionMap[input.field]
          column = { ...column, options: formatOptions(options) }
        }
        return column
      })

      // this.$forceUpdate() 没有效果 只能用下面这种方式刷新页面数据
      this.items = this.list.map(item => {
        return item
      })
    },
    // 格式化options
    formatOptions(input) {
      input.options = formatOptions(input.options)
      return input
    },
    // 表单提交
    handleFormSubmit(...params) {
      this.$emit('form-submit', ...params)
    },
    // 取消表单提交
    handleFormCancel(...params) {
      this.$emit('form-cancel', ...params)
    },
    parseImageList(images) {
      images = images === '' ? [DEFAULT_IMAGE] : images
      if (images instanceof Array) {
        return images
      } else {
        return jsonParse(images)
      }
    },
    parseFileList(files) {
      files = files === '' ? [] : files
      if (files instanceof Array) {
        return files
      } else {
        return jsonParse(files)
      }
    }
  }
}
</script>
<style scoped>
  .images-wrap {
    overflow: auto;
    max-height: 100px;
  }
  .images-item {
    max-width: 80px;
    max-height: 120px;
    display: inline-block;
  }
  .images-item-small {
    max-width: 40px;
    max-height: 60px;
    display: inline-block;
  }
  .images-body {
    overflow: auto;
    max-height: 400px;
  }
</style>
